package com.wang.java.thread.threadpool;

import java.util.concurrent.*;

/**
 * 线程池测试类
 * 顶级接口：
 * public interface Executor：顶级线程池接口，只有一个函数：void execute(Runnable command);
 * public ExecutorService extends Executor ：扩展了线程池接口，shutdown()、shutdownNow()、submit()等接口
 * 线程池抽象类和实现：
 * public abstract class AbstractExecutorService implements ExecutorService：抽象类，对ExecutorService部分接口做了默认实现
 * public class ThreadPoolExecutor extends AbstractExecutorService：线程池类（核心重点）
 * 调度线程池接口和实现：
 * public interface ScheduledExecutorService extends ExecutorService：增强接口，基于线程池接口扩展了schedule()方法
 * public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService：调度线程池类
 * 线程池工厂类：
 * public class Executors：线程池工厂类，底层基于ThreadPoolExecutor类实现，方便创建不同类型的线程池
 * 注意：阿里巴巴规范中不推荐使用Executors创建线程池，推荐使用ThreadPoolExecutor手动创建线程池
 * Executors存在以下问题：
 * 问题1：使用类似LinkedBlockingQueue的无界队列，可能造成OOM
 * 问题2.线程最大数量指定为Integer.MAX_VALUE，可能造成OOM
 * <p>
 * 线程池的参数：
 * int corePoolSize：核心线程数
 * int maximumPoolSize：最大线程数
 * long keepAliveTime：线程空闲后的存活时间（默认指非核心线程，若设置allowCoreThreadTimeOut=true，则核心线程空闲超过keepAliveTIme也会被回收）
 * TimeUnit unit：存活时间单位
 * BlockingQueue<Runnable> workQueue：线程池队列 TODO
 * <p>
 * threadFactory：线程工厂，线程池中线程的创建方式 TODO
 * <p>
 * RejectedExecutionHandler handler：线程拒绝策略 TODO
 * 触发场景：	1.线程池shutDown 2.达到最大线程 && 队列满
 * AbortPolicy：直接抛出RejectedExecutionException异常
 * CallerRunsPolicy：如果线程池没有shutdown()，则直接使用调用者线程运行这个任务
 * DiscardPolicy：什么也不做
 * DiscardOldestPolicy：若线程池没有shutdown()，则丢弃最老的一条数据（队列头一条）。然后execute()
 */
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
//        testFixedThreadPool();
//        testCachedThreadPool();

//        testSingleThreadPool();
//        testScheduleExecutorService();
//        testSingleThreadSchedulePool();
//        testWorkStealingPool();
    }

    /**
     * 工作窃取线程池
     */
    private static void testWorkStealingPool() throws InterruptedException {
        ExecutorService workStealingPool = Executors.newWorkStealingPool();
        for (int i = 0; i < 2; i++) {
            workStealingPool.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        workStealingPool.shutdown();
    }

    /**
     * 单一调度线程池
     */
    private static void testSingleThreadSchedulePool() throws InterruptedException {
        ExecutorService singleThreadScheduledExecutor = Executors.newSingleThreadScheduledExecutor();
        for (int i = 0; i < 2; i++) {
            singleThreadScheduledExecutor.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        singleThreadScheduledExecutor.shutdown();
    }

    /**
     * 调度线程池
     */
    private static void testScheduleExecutorService() throws InterruptedException {
        ExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);
        for (int i = 0; i < 2; i++) {
            scheduledExecutorService.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        scheduledExecutorService.shutdown();
    }

    /**
     * 单一线程池
     */
    private static void testSingleThreadPool() throws InterruptedException {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 2; i++) {
            singleThreadExecutor.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        singleThreadExecutor.shutdown();
    }

    /**
     * 可缓存的线程池
     * 有可用的线程就不会新建线程处理任务
     * @throws InterruptedException
     */
    private static void testCachedThreadPool() throws InterruptedException {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 2; i++) {
            cachedThreadPool.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        cachedThreadPool.shutdown();
    }

    /**
     * 定长线程池
     * 当活动线程数 < 核心线程数，新建线程处理任务
     *
     * @throws InterruptedException
     */
    private static void testFixedThreadPool() throws InterruptedException {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
        for (int i = 0; i < 2; i++) {
            fixedThreadPool.submit(() -> System.out.println(Thread.currentThread().getName()));
            TimeUnit.SECONDS.sleep(1);
        }
        fixedThreadPool.shutdown();
    }
}